package Model;
import java.util.ArrayList;


public class Newtons {
	
	private ArrayList<Double> xList;
	private ArrayList<Double> yList;
	private ArrayList<Double> yPrimeList;
	
	// f(x) part
	private ArrayList<Double> yCoefList;
	private ArrayList<Double> yPowerList;
	// f'(x) part
	private ArrayList<Double> yPrimeCoefList;
	private ArrayList<Double> yPrimePowerList;
	private ArrayList<Double> thresholdList;
	private ArrayList<Double> trueXList;
	private ArrayList<Double> trueYList;
	
	
	private double x, y, yprime;
	private int nIteration;
	private double threshold;
	
	public Newtons(){
		xList = new ArrayList<Double>();
		yList = new ArrayList<Double>();
		yPrimeList = new ArrayList<Double>();
		yCoefList = new ArrayList<Double>();
		yPowerList = new ArrayList<Double>();
		yPrimeCoefList = new ArrayList<Double>();
		yPrimePowerList = new ArrayList<Double>();
		thresholdList = new ArrayList<Double>();
		trueYList= new ArrayList<Double>();
		trueXList= new ArrayList<Double>();
	}
	
	public Newtons(Double x, int nIteration, String function, Double threshold) {
		
		this.x = x;
		this.nIteration = nIteration;
		this.threshold = threshold;
		this.parseFunction(function);
	}
	
	public void parseFunction(String function){
		String[] temp = function.split(" ");
		// f(x) part
		for(int i = 0; i < temp.length; i+=2)
		{
			yCoefList.add(Double.parseDouble(temp[i]));
			yPowerList.add(Double.parseDouble(temp[i+1]));
		}

		// f'(x) part
		for(int i = 0; i < yCoefList.size(); i++)
		{
			yPrimeCoefList.add(yCoefList.get(i) * yPowerList.get(i));
			yPrimePowerList.add(yPowerList.get(i)-1);	
		}
	}
	
	public double computeY(double x, ArrayList<Double> coefList, ArrayList<Double> powerList){
		double result = 0;
		for(int i = 0; i < coefList.size(); i++)
			result += coefList.get(i) * Math.pow(x, powerList.get(i));
		
		return result;
	}
	
	public void computeNewtons(){
		double tempVal = x-15;
		while(tempVal <= nIteration+15)
		{
			trueXList.add(tempVal);
			trueYList.add(computeY(tempVal, yCoefList, yPowerList));
			tempVal++;
		}
		
		
		double currentthreshold = Double.MAX_VALUE;
		while(nIteration > 0 && currentthreshold > threshold)
		{
			thresholdList.add(currentthreshold);
			y = computeY(x, yCoefList, yPowerList); 
			yprime = computeY(x, yPrimeCoefList, yPrimePowerList);
			xList.add(x);
			yList.add(y);
			yPrimeList.add(yprime);
			double temp = x - (y / yprime);
			currentthreshold = Math.abs(x - temp);
			x = temp;
			nIteration--;
		}
		this.printEverything();
	}
	
	public void printEverything(){
		for(int i = 0; i < xList.size(); i++){
			System.out.println("x="+xList.get(i)+" y="+ yList.get(i) + " yPrime =" + yPrimeList.get(i));
			System.out.println("threshold = " + thresholdList.get(i));
			System.out.println("x="+trueXList.get(i)+" y="+ trueYList.get(i));
		}
	}
	
	public void clearList(){
		xList.clear();
		yList.clear();
		yPrimeList.clear();
		yCoefList.clear();
		yPowerList.clear();
		yPrimeCoefList.clear();
		yPrimePowerList.clear();
		thresholdList.clear();
		trueXList.clear();
		trueYList.clear();
	}
	
	public ArrayList<Double> getTrueXList(){
		return trueXList;
	}
	
	public ArrayList<Double> getTrueYList(){
		return trueYList;
	}
	
	public ArrayList<Double> getxList(){
		return xList;
	}
	
	public ArrayList<Double> getyList(){
		return yList;
	}
	
	public ArrayList<Double> getyPrimeList(){
		return yPrimeList;
	}
	
	public ArrayList<Double> getThresholdList(){
		return thresholdList;
	}
	
	public void setValues(Double x, int nIteration, String function, Double threshold) {
		this.x = x;
		this.nIteration = nIteration;
		this.threshold = threshold;
		this.parseFunction(function);
	}
	
	public static void main(String args[]){
		String function = "1 2 -78.8 0";
		Newtons newtons = new Newtons(6.0, 10, function, 0.0248);
		newtons.computeNewtons();
	}

}
